package com.share.four.netty.http.helloworld;

import static io.netty.handler.codec.http.HttpHeaderNames.CONNECTION;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
import static io.netty.handler.codec.http.HttpResponseStatus.CONTINUE;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderUtil;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.util.ReferenceCountUtil;

/*
 * ChannelHandlerAdapter.class--->适配器设计模式：目的是不用重写接口中的每个方法，只重写需要的
 */
public class ServerHandler extends ChannelHandlerAdapter{

	/* 
	 * description： 在不接受任何请求时, 只是在连接被创建时，会执行此方法
	 */
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		System.out.println("server channel active");
	}

	/* 
	 * @description: 每当从客户端收到新的数据时，这个方法会在收到消息时被调用
	 * msg: client端发送过来的数据
	 * ctx: server端与client端的channel
	 */
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

		try {
			if (msg instanceof HttpRequest) {
				HttpRequest req = (HttpRequest) msg;
				if (HttpHeaderUtil.is100ContinueExpected(req)) {
					ctx.writeAndFlush(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE));
				}

				boolean keepAlive = HttpHeaderUtil.isKeepAlive(req);
				DefaultFullHttpResponse response = 
						new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.copiedBuffer("Hello World".getBytes()));
				response.headers().set(CONTENT_TYPE, "text/plain");
				response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes());

				if (!keepAlive) {
					ctx.writeAndFlush(response).addListeners(ChannelFutureListener.CLOSE);
				} else {
					response.headers().set(CONNECTION, HttpHeaderValues.KEEP_ALIVE);
					ctx.writeAndFlush(response);
				}
			}

		} finally {
			//DISCARD服务(丢弃服务，指的是会忽略所有接收的数据的一种协议)
			ReferenceCountUtil.release(msg);
		}

	}

	/* 
	 * @description: 当Netty由于IO错误或者处理器在处理事件时抛出的异常时,该方法被调用
	 */
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		cause.printStackTrace();
		ctx.close();
	}


}
